package com.woniuxy.shiro.configuration;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import com.woniuxy.shiro.filter.OrFilter;
import com.woniuxy.shiro.realm.CustomRealm;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.mgt.DefaultSessionManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.ShiroFilter;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.Filter;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

@Configuration  //配置类标志
public class ShiroConfiguration {
    private static  final Logger logger = LoggerFactory.getLogger(ShiroConfiguration.class);
    //1.配置realm：域对象，调用service获取用户的账号密码、权限信息  自定义
    @Bean   //<bean>  默认以方法名作为id：此处就是realm
    public CustomRealm realm(){
        logger.info("创建realm");
        return new CustomRealm();
    }

    //2.安全管理器（核心）
    //7.2.将session管理器交给安全管理器管理
    @Bean   //参数将相当于  <property ref = "realm">
    public SecurityManager securityManager(CustomRealm realm,DefaultWebSessionManager sessionManager){
        DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
        //设置realm
        manager.setRealm(realm);
        //设置session管理器

        manager.setSessionManager(sessionManager);
        return manager;
    }

    /**
     * 3.shiro过滤器
     * 主要来指定哪些请求需要认证、哪些不需要、哪些需要什么样的权限
     */

    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager,OrFilter orFilter){
        ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
        //5.注册自定义的过滤器
        //javax.servlet.Filter
        Map<String, Filter> filterMap = new HashMap<>();
        filterMap.put("or",orFilter);
        factoryBean.setFilters(filterMap);

        //配置安全管理器
        factoryBean.setSecurityManager(securityManager);
        //配置没有权限时要请求的url(页面、后台url)
        factoryBean.setUnauthorizedUrl("/jump/unauthorized");//如果在后台跳 表明前后端不分离
        //需要登录但是又没有登录时，自动跳转到指定的页面获取请求后台的url
        factoryBean.setLoginUrl("/jump/toLogin");

        //设置过滤器链
        //HashMap 无序   LinkedHashMap 有序
        Map<String,String> map = new LinkedHashMap<>();
        //key：url    value：标签shiro的过滤器
        //anon是shiro的内置过滤器的名字，是anonymous单词前四个字母  表示能够匿名访问
        //main.html
        map.put("/login.html","anon");
        map.put("/user/login","anon");
        map.put("/user/regist","anon");

        //静态资源放行
        map.put("/html/*","anon");
        map.put("/css/*","anon");
        map.put("/js/*","anon");
        map.put("/images/*","anon");

        //role 角色，当请求相关url时，匹配到的过滤器为roles表示
        //访问该URL必须是[]中指定的角色
        //[]中的角色名字是程序员自定义
        //当shiro识别到roles过滤器时会自动调用realm中获取授权信息的方法
        map.put("/admin.html","roles[admin]");
        map.put("/teacher.html","roles[teacher]");
        map.put("/student.html","roles[student]");
        //两个角色必须都同时拥有才能访问
        map.put("/adminAndTeacher.html","roles[admin,teacher]");
        //表示只要具备其中任何一个角色都可以访问
        map.put("/adminOrTeacher.html","or[admin,teacher]");


        //权限 perm s     permission缩写
        map.put("/teacher/add","perms[teacher:add]");

        //使用记住我过滤器
        map.put("/rm.html","user");

        //注销操作
        map.put("/user/logout","logout");

        //除开以上情况以外的
        //authc也是shiro内置过滤器的名字，是Authentication单词的缩写  表示需要认证（登录）之后才能访问
        map.put("/**","authc");

        //
        factoryBean.setFilterChainDefinitionMap(map);
        //
        return factoryBean;
    }
    //4.创建自定义过滤器bean
    @Bean
    public OrFilter orFilter(){
        return new OrFilter();
    }

    //6.配置shiro注解的支持：shiro注解基于AOP实现的
    //6.1配置通知
    @Bean
    public AuthorizationAttributeSourceAdvisor advisor(SecurityManager securityManager){
        AuthorizationAttributeSourceAdvisor sourceAdvisor =
                new AuthorizationAttributeSourceAdvisor();
        sourceAdvisor.setSecurityManager(securityManager);
        return sourceAdvisor;
    }
    //6.2.创建代理器
    @Bean
    public DefaultAdvisorAutoProxyCreator creator(){
        DefaultAdvisorAutoProxyCreator proxyCreator = new DefaultAdvisorAutoProxyCreator();
        //开启目标代理
        proxyCreator.setProxyTargetClass(true);
        return proxyCreator;
    }
    //7.配置session管理器
    //7.1.创建管理器
    @Bean
    public DefaultWebSessionManager sessionManager(){
        DefaultWebSessionManager manager = new DefaultWebSessionManager();
        //过期时间：单位毫秒
        manager.setGlobalSessionTimeout(1000*60*60*24);
        //删除已经过期的session
        manager.setDeleteInvalidSessions(true);
        return manager;
    }

    //8.配置shiro标签的方言
    @Bean
    public ShiroDialect dialect(){
        return new ShiroDialect();
    }
}
